﻿namespace Sai.Test
{
	using Sai.Core;
	using Xunit;
	using NSubstitute;
	using Sai.Core.Introspection;
	using System.Collections.Generic;
    using Sai.Test.XUnit;

	public class TypeDifferenceFacts
	{
        public class TheTypeTaxonomyProperty
        {
            [Fact, InMemoryTest]
            public void Returns_Single_TopLevel_Item_For_Taxonomy_Change()
            {
                var diff = new TypeDifference();
                diff.Name = "MyLib.TestClass";
                diff.AssemblyIdentifier = "12345";
                diff.SummaryIdentifier = "67890";

                var code = Substitute.For<ISourceCodeProvider>();
                code.ToCode().Returns(new SourceCode());

                var message = Substitute.For<IMessageProvider>();
                message.Message.Returns("Was class now am an interface");

                diff.IdentifiedChange(TypeChangeReason.TypeTaxonomy, code, message);

                Assert.Equal(1, diff.TypeTaxonomy.Count);
            }
        }


		public class TheToXmlMethod
		{
			[Fact, InMemoryTest]
			public void Creates_MultiLine_Format_Omitting_Null_Elements()
			{
				var diff = new TypeDifference();
				diff.Name = "MyLib.TestClass";
				diff.AssemblyIdentifier = "12345";
				diff.SummaryIdentifier  = "67890";

				string output = diff.ToXml();

				Assert.Contains("<TypeDifference ", output);
				Assert.Contains("Name=\"MyLib.TestClass\"", output);
				Assert.Contains(" ID=\"", output);
				Assert.Contains(" AssemblyID=\"12345\"", output);
				Assert.Contains(" SummaryID=\"67890\"", output);
				Assert.DoesNotContain("<TypeTaxonomy />", output);
                Assert.DoesNotContain("<InheritanceChanged />", output);
                Assert.DoesNotContain("<ConstantsObsolete />", output);
                Assert.DoesNotContain("<ConstantsRemoved />", output);
                Assert.DoesNotContain("<ConstantsChanged />", output);
                Assert.DoesNotContain("<ConstantsAdded />", output);
                Assert.DoesNotContain("<FieldsObsolete />", output);
                Assert.DoesNotContain("<FieldsRemoved />", output);
                Assert.DoesNotContain("<FieldsChanged />", output);
                Assert.DoesNotContain("<FieldsAdded />", output);
                Assert.DoesNotContain("<ConstructorsObsolete />", output);
                Assert.DoesNotContain("<ConstructorsRemoved />", output);
                Assert.DoesNotContain("<ConstructorsChanged />", output);
                Assert.DoesNotContain("<ConstructorsAdded />", output);
                Assert.DoesNotContain("<EventsObsolete />", output);
                Assert.DoesNotContain("<EventsRemoved />", output);
                Assert.DoesNotContain("<EventsChanged />", output);
                Assert.DoesNotContain("<EventsAdded />", output);
                Assert.DoesNotContain("<PropertiesObsolete />", output);
                Assert.DoesNotContain("<PropertiesRemoved />", output);
                Assert.DoesNotContain("<PropertiesChanged />", output);
                Assert.DoesNotContain("<PropertiesAdded />", output);
                Assert.DoesNotContain("<IndexersObsolete />", output);
                Assert.DoesNotContain("<IndexersRemoved />", output);
                Assert.DoesNotContain("<IndexersChanged />", output);
                Assert.DoesNotContain("<IndexersAdded />", output);
                Assert.DoesNotContain("<MethodsObsolete />", output);
                Assert.DoesNotContain("<MethodsRemoved />", output);
                Assert.DoesNotContain("<MethodsChanged />", output);
                Assert.DoesNotContain("<MethodsAdded />", output);
                Assert.DoesNotContain("<ValuesRemoved />", output);
                Assert.DoesNotContain("<ValuesAdded />", output);
                Assert.DoesNotContain("</TypeDifference>", output);
			}

			[Fact, InMemoryTest]
			public void Include_FieldsRemoved_Tag_When_Field_Removed()
			{
				var diff = new TypeDifference();
				diff.Name = "MyLib.TestClass";
				diff.AssemblyIdentifier = "12345";
				diff.SummaryIdentifier = "67890";

				var code = Substitute.For<ISourceCodeProvider>();
				code.ToCode().Returns(new SourceCode());

				diff.IdentifiedChange(new UnaryTypeChange(TypeChangeReason.FieldRemoved, code));  

				string output = diff.ToXml();

				Assert.Contains("<FieldsRemoved>", output);
                Assert.Contains("</FieldsRemoved>", output);
			}

			[Fact, InMemoryTest]
            public void Include_TypeTaxonomy_Tag_When_Interface_Removed()
			{
				var diff = new TypeDifference();
				diff.Name = "MyLib.TestClass";
				diff.AssemblyIdentifier = "12345";
				diff.SummaryIdentifier = "67890";

				var typeList = new List<TypeName>();
				typeList.Add(new TypeName(new FullyQualifiedName("System.IDisposable")));

                foreach (var t in typeList)
                {
                    diff.IdentifiedChange(TypeChangeReason.TypeInterfaceRemoved, t, "Removed");
                }

				string output = diff.ToXml();

                Assert.Contains("<TypeTaxonomy>", output);
                Assert.Contains("</TypeTaxonomy>", output);
			}

			[Fact, InMemoryTest]
			public void Include_FieldsObsolete_Tag_When_Field_Obsolete()
			{
				var diff = new TypeDifference();
				diff.Name = "MyLib.TestClass";
				diff.AssemblyIdentifier = "12345";
				diff.SummaryIdentifier = "67890";

				var code = Substitute.For<ISourceCodeProvider>();
                code.ToCode().Returns(new SourceCode());

                diff.IdentifiedChange(TypeChangeReason.FieldObsolete, code, "Not used anymore");

				string output = diff.ToXml();

                Assert.Contains("<FieldsObsolete>", output);
                Assert.Contains("<Reason>FieldObsolete</Reason>", output);
                Assert.Contains("<Message>Not used anymore</Message>", output);
                Assert.Contains("</FieldsObsolete>", output);
			}
		}
	}
}
